<?php
    if (!defined('__IS_LEAF__')) exit('Access Denied!');

    /**
     * 错误处理类，主要用于捕获错误，禁止错误输出。然后并从系统error()函数接手，让错误由此类处理
     * 有三种级别的错误处理：致命、警告、提示
     * 用于与core衔接。由core调用init之后，本类提供静态方法供系统使用错误处理机制
     * 原理同Monitor监控类类似
     * 注意：由于系统级的错误也交由框架处理，所以框架本身出错，可能会出现页面空白显示，出现这种情况，说明已发生致命错误，此时，在init设置error_reporting(-1)即可。
     * 为了最大限度的将错误交由框架处理，那么应最大限度的实现功能解耦合！
     */

    class Error {

        static private $errorInfo=array();

        /**
         * 设置错误信息属性
         */
        static private function setErrorInfo($errorInfo){
            self::$errorInfo = $errorInfo;
        }

        /**
         * 错误处理初始化
         * 将因为错误导致的程序中断而无法捕获的错误，交由自定义函数捕获处理，同时，用户自定义的错误也由此处理
         */
        static public function init(){
            //获取系统配置中的报错模式，如果该设置的不合法，设置为0
            $error_reporting_arr = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_WARNING, E_NOTICE, 0, -1);
            $error_reporting = intval(C('error_reporting'));
            $error_reporting = (!in_array($error_reporting, $error_reporting_arr)) ? -1 : $error_reporting;
            error_reporting($error_reporting);
            //如果设置了error_sys_to_leaf为1，则代表将系统和用户错误交由框架处理
            if(C('error_sys_to_leaf')=='1'){
                //捕获用户自定义级别错误
                set_error_handler('Error::catchUserError', E_ALL);
                //捕获系统级别错误
                register_shutdown_function('Error::catchSysError');
            }
        }

        /**
         * 获取用户自定义级别的错误，设置错误信息属性，调用统一处理方法
         */
        static public function catchUserError($errno, $errstr, $errfile, $errline){
            //errorInfo与error_get_last获取的错误信息格式保持一致
            $errorInfo = array('type'=>$errno, 'message'=>$errstr, 'file'=>$errfile, 'line'=>$errline);
            self::setErrorInfo($errorInfo);
            self::catchError('e_user');
        }

        /**0
         * 获取系统级别的错误，设置错误信息属性，调用统一处理方法
         */
        static public function catchSysError(){
            $errorInfo = error_get_last();
            self::setErrorInfo($errorInfo);
            self::catchError('e_sys');
        }

        /**
         * 错误统一处理方法
         * 在脚本结束时，捕获错误信息，并处理
         * 此方法为public方法，只是因为init调用的时候，其内部函数的参数不能为self
         * @param string $level 错误类型，是用户自定义方式错误引用该函数，还是系统级别错误引用的该函数
         */
        static private function catchError($level){
            global $leaf;
            $errorInfo = self::$errorInfo;
            //打印错误
            //设置一个数组，判断错误type在没在数组中，在则写入日志信息，否则会出现脚本结束也写错误日志
            //设置严重错误的错误数组
            $error_array = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR);
            //如果是严重错误，记录错误日志，并中断执行
            if(in_array($errorInfo['type'], $error_array)){
                //记录错误信息，目前是记录所有的错误信息
                if(C('error_log_record')==true){
                    self::errorRecord($errorInfo, 'leaf');
                }
                P($errorInfo);
                //模拟PHP自己错误退出，不能让致命错误发生后还尅继续运行
                exit();
            }
        }

        /**
         * 错误日志记录
         * 记录用户级&系统级错误、网站错误等
         * @param array $errorInfo 错误信息
         * @param string $type 错误分类
         */
        static private function errorRecord($errorInfo ,$type='leaf'){
            Log::errorLogRecord($errorInfo, $type='leaf');
        }

    }